package cn.liyunqi.controller;

import cn.liyunqi.BizException;
import cn.liyunqi.util.FileUtil;
import cn.liyunqi.util.StringUtil;
import cn.liyunqi.util.TimeUtil;
import cn.liyunqi.view.AlertUtil;
import com.baidu.aip.speech.AipSpeech;
import com.baidu.aip.speech.TtsResponse;

import com.github.nobodxbodon.zhconverter.简繁转换类;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.input.InputEvent;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.mp3.MP3AudioHeader;
import org.jaudiotagger.audio.mp3.MP3File;
import org.json.JSONObject;

import java.awt.*;
import java.io.*;
import java.math.BigDecimal;
import java.net.URL;

import java.util.HashMap;
import java.util.ResourceBundle;


public class MainUIController extends BaseFXController {

    @FXML
    private Button begianCreateBtn;

    @FXML
    private Button filePathBtn;

    @FXML
    private Label filePathLab;

    @FXML
    private TextField fileNameTxt;

    @FXML
    private ScrollBar spdScroll;

    @FXML
    private ScrollBar pitScroll;

    @FXML
    private ScrollBar volScroll;

    @FXML
    private ToggleGroup perGroup;

    @FXML
    private Label spdLab;

    @FXML
    private Label pitLab;

    @FXML
    private Label volLab;

    @FXML
    private ProgressBar progressBar;

    @FXML
    private TextArea setTextTxt;

    private static String R = System.getProperty("line.separator");

    private void disableHandle(boolean flg){
        begianCreateBtn.setDisable(flg);
        setTextTxt.setDisable(flg);
        setTextTxt.setDisable(flg);
        filePathBtn.setDisable(flg);
        fileNameTxt.setDisable(flg);
        spdScroll.setDisable(flg);
        pitScroll.setDisable(flg);
        volScroll.setDisable(flg);

        for (int i = 0; i < perGroup.getToggles().size(); i++) {
            RadioButton radioButton= (RadioButton) perGroup.getToggles().get(i);
            radioButton.setDisable(flg);
        }
    }

    public void initialize(URL location, ResourceBundle resources) {
        //portRdoGroup.getToggles().get(port - 1).setSelected(true);
        //spd	String	语速，取值0-9，默认为5中语速	否
        spdScroll.setValue(5);
        spdLab.setText("5");
        //pit	String	音调，取值0-9，默认为5中语调	否
        pitScroll.setValue(5);
        pitLab.setText("5");
        //vol	String	音量，取值0-15，默认为5中音量	否
        volScroll.setValue(5);
        volLab.setText("5");
        //per	String	发音人选择, 0为女声，1为男声，
        //3为情感合成-度逍遥，4为情感合成-度丫丫，默认为普通女
        perGroup.getToggles().get(2).setSelected(true);

        spdScroll.addEventHandler(InputEvent.ANY, new ScrollChangeHandler(spdLab,spdScroll));
        pitScroll.addEventHandler(InputEvent.ANY, new ScrollChangeHandler(pitLab,pitScroll));
        volScroll.addEventHandler(InputEvent.ANY, new ScrollChangeHandler(volLab,volScroll));

        progressBar.setProgress(0);
    }

    private class ScrollChangeHandler implements EventHandler<Event>{
        private Label label;
        private ScrollBar bar;
        ScrollChangeHandler(Label label ,ScrollBar bar){
            super();
            this.label = label;
            this.bar = bar;
        }

        @Override
        public void handle(Event evt) {
            double value = bar.getValue();
            label.setText(((int) value) + "");
        }
    }

    public Task createWorker(String text,String path,String fileName,int spd ,int pit,int vol ,int per,boolean coverFlg) {


        return new Task() {

            public static final int LENGTH = 1022;

            //设置APPID/AK/SK
            public static final String APP_ID = "11386622";
            public static final String API_KEY = "zT2SXTHZZ9eB9aMDaBNnsiaz";
            public static final String SECRET_KEY = "FCnSnlDuKG9A0P5kA3gLqWdz3goXvgDs";

            @Override
            protected Object call() throws Exception {

                //FileWriter srtfw = null;
                BufferedWriter srtbw = null;
                OutputStream srtos = null;
                OutputStreamWriter srtosw = null;

                //FileWriter lrcfw = null;
                BufferedWriter lrcbw = null;
                OutputStream lrcos = null;
                OutputStreamWriter lrcosw = null;

                try {

                    boolean appendFlg = !coverFlg;

                    disableHandle(true);

                    //先将文本备份
                    String temp = new String(text);

                    BigDecimal textLen = new BigDecimal(temp.length());

                    String srtfileName = fileName.substring(0,fileName.length() - 4 ) + ".srt";
                    String lrcfileName = fileName.substring(0,fileName.length() - 4 ) + ".lrc";

                    //字幕文件处理
                    boolean srtosFlg = false;
                    boolean lrcosFlg = false;
                    File srtfile = new File(path + "/" + srtfileName);
                    if(!FileUtil.fileIsExists(path + "/" + srtfileName)){
                        srtfile.createNewFile();
                        srtos = new FileOutputStream(srtfile,appendFlg);
                        srtos.write(new byte[]{(byte)0xEF, (byte)0xBB, (byte)0xBF});
                        srtosFlg = true;
                    }


                    File lrcfile = new File(path + "/" + lrcfileName);
                    if(!FileUtil.fileIsExists(path + "/" + lrcfileName)){
                        lrcfile.createNewFile();
                        lrcos = new FileOutputStream(lrcfile,appendFlg);
                        lrcosw = new OutputStreamWriter(lrcos, "UTF-8");
                        //lrcfw = new FileWriter(lrcfile, appendFlg);
                        lrcbw = new BufferedWriter(lrcosw);

                        lrcos.write(new byte[]{(byte)0xEF, (byte)0xBB, (byte)0xBF});
                        lrcosFlg  =true;
                        lrcbw.write("[by:kiss598652881@sina.com]" + R);
                    }

//                    if(lrcfw == null){
//                        lrcfw = new FileWriter(lrcfile, appendFlg);
//                    }
                    if(lrcos == null){
                        lrcos = new FileOutputStream(lrcfile,appendFlg);
                    }
                    if(lrcosw == null){
                        lrcosw = new OutputStreamWriter(lrcos, "UTF-8");
                    }
                    if(lrcbw == null){
                        lrcbw = new BufferedWriter(lrcosw);
                    }
                    if(srtos == null) {
                        srtos = new FileOutputStream(srtfile, appendFlg);
                    }
                    if(coverFlg){
                        if(!srtosFlg && srtos != null){
                            srtos.write(new byte[]{(byte)0xEF, (byte)0xBB, (byte)0xBF});
                        }
                        if(!lrcosFlg && lrcos != null){
                            lrcos.write(new byte[]{(byte)0xEF, (byte)0xBB, (byte)0xBF});
                        }
                    }
                    srtosw = new OutputStreamWriter(srtos, "UTF-8");

                    //srtfw = new FileWriter(srtfile, appendFlg);
                    srtbw = new BufferedWriter(srtosw);

                    Integer srtrowNum = 0;
                    //如果追加的情况下获取最后第四行的行号
                    if(!coverFlg){
                        FileReader fr = new FileReader(srtfile);
                        BufferedReader br = new BufferedReader(fr);

                        String line = null;
                        int lineNum = 0;
                        while ((line = br.readLine()) != null) {

                            if(lineNum == 0){
                                try {
                                    srtrowNum = new Integer(line);
                                }catch (Exception e){
                                    System.out.println("字幕最后行号寻找失败");
                                }
                            }
                            lineNum = (lineNum + 1 ) % 4;
                        }
                    }

                    // 初始化一个AipSpeech
                    AipSpeech client = new AipSpeech(APP_ID, API_KEY, SECRET_KEY);
                    // 可选：设置网络连接参数
                    client.setConnectionTimeoutInMillis(2000);
                    client.setSocketTimeoutInMillis(60000);

                    // 可选：设置代理服务器地址, http和socket二选一，或者均不设置
                    //client.setHttpProxy("proxy_host", proxy_port);  // 设置http代理
                    //client.setSocketProxy("proxy_host", proxy_port);  // 设置socket代理

                    // 可选：设置log4j日志输出格式，若不设置，则使用默认配置
                    // 也可以直接通过jvm启动参数设置此环境变量
                    //System.setProperty("aip.log4j.conf", "path/to/your/log4j.properties");

                    HashMap<String, Object> options = new HashMap<String, Object>();
                    options.put("spd", spd + "");
                    options.put("pit", pit + "");
                    options.put("vol", vol + "");
                    options.put("per", per + "");//发音人选择, 0为女声，1为男声，3为情感合成-度逍遥，4为情感合成-度丫丫，默认为普通女


                    //将文本切分
                    while (temp.length() > 0) {
                        //合成文本长度必须小于1024字节，如果本文长度较长，可以采用多次请求的方式。文本长度不可超过限制
                        String createValue = temp.substring(0, temp.length() < LENGTH ? temp.length() : LENGTH);
                        //找到最大程度内的符号
                        int index = 0;
                        int eDouhao = createValue.indexOf(",");
                        int eJuhao = createValue.indexOf(".");
                        int eWenhao = createValue.indexOf("?");
                        int eGantan = createValue.indexOf("!");
                        int cDouhao = createValue.indexOf("，");
                        int cJuhao = createValue.indexOf("。");
                        int cWenhao = createValue.indexOf("？");
                        int cGantan = createValue.indexOf("！");

                        if(eDouhao > index){
                            index = eDouhao;
                        }
                        if(eJuhao > index){
                            index = eJuhao;
                        }
                        if(cDouhao > index){
                            index = cDouhao;
                        }
                        if(cJuhao > index){
                            index = cJuhao;
                        }
                        if(eWenhao > index){
                            index = eWenhao;
                        }
                        if(eGantan > index){
                            index = eGantan;
                        }
                        if(cWenhao > index){
                            index = cJuhao;
                        }
                        if(cGantan > index){
                            index = cJuhao;
                        }
                        if(index <= 0){
                            index = createValue.length();
                        }
                        createValue = temp.substring(0, index);
                        temp = temp.substring(index);

                        // 调用接口
                        TtsResponse res = client.synthesis(createValue, "zh", 1, options);
                        byte[] data = res.getData();
                        JSONObject res1 = res.getResult();
                        if (data != null) {
                            DataOutputStream out = null;

                            //获取上一次音频文件的时长
                            double mp3LenOld = 0;

                            try {
                                //追加的方式
                                if(appendFlg){
                                    //而且文件存在
                                    if(FileUtil.fileIsExists(path + "/" + fileName)){
                                        File file = new File(path + "/" + fileName);
                                        MP3File f = (MP3File)AudioFileIO.read(file);
                                        MP3AudioHeader audioHeader = (MP3AudioHeader)f.getAudioHeader();
                                        mp3LenOld = audioHeader.getPreciseTrackLength();
                                    }
                                }

                                out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(path + "/" + fileName, appendFlg)));
                                out.write(data);
                            } catch (Exception e) {
                                e.printStackTrace();
                            } finally {
                                if (out != null) {
                                    try {
                                        out.close();
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                }

                                //获取写入后的时长
                                if(FileUtil.fileIsExists(path + "/" + fileName)){
                                    File file = new File(path + "/" + fileName);
                                    MP3File f = (MP3File)AudioFileIO.read(file);
                                    MP3AudioHeader audioHeader = (MP3AudioHeader)f.getAudioHeader();
                                    double mp3LenNew = audioHeader.getPreciseTrackLength();

                                    //备份字幕使用
                                    createValue = createValue.replaceAll(" ","");
                                    createValue = createValue.replaceAll("　","");

                                    createValue = StringUtil.replaceBlank(createValue);

                                    srtrowNum = writeTextInLrcAndSrt(mp3LenOld,mp3LenNew,createValue,srtbw,lrcbw,srtrowNum);

                                }

                                appendFlg = true;

                                //Thread.sleep(2000);
                                updateMessage("2000 milliseconds");
                                //计算滚动条
                                BigDecimal tempLen = new BigDecimal(temp.length());

                                updateProgress(new BigDecimal(1000).subtract(tempLen.divide(textLen, 5, BigDecimal.ROUND_HALF_DOWN).multiply(new BigDecimal(1000))).longValue(), 1000);

                            }
                        }
                        if (res1 != null) {
                            System.out.println(res1.toString(2));

                            //500	不支持的输入
                            //501	输入参数不正确
                            //502	token验证失败
                            //503	合成后端错误
                            String errNo = res1.get("err_no").toString();
                            if (errNo != null) {
                                switch (errNo) {
                                    case "500":
                                        throw new BizException("转换失败：不支持的输入");
                                    case "501":
                                        throw new BizException("转换失败：输入参数不正确");
                                    case "502":
                                        throw new BizException("转换失败：token验证失败");
                                    case "503":
                                        throw new BizException("转换失败：合成后端错误");
                                }
                            }
                        }
                    }

                    AlertUtil.showInfoAlert("转化成功");
                    updateProgress(1000, 1000);

                }catch (BizException biz){
                    AlertUtil.showErrorAlert(biz.getMessage());
                }catch (Exception ex){
                    ex.printStackTrace();
                    System.out.println(ex);
                    AlertUtil.showErrorAlert("转化失败");
                }finally {
                    if(srtbw != null){
                        srtbw.flush();
                        srtbw.close();
                    }
                    if(srtosw != null){
                        //srtosw.flush();
                        srtosw.close();
                    }
                    if(srtos != null){
                        srtos.close();
                    }
                    /*if(srtfw != null){
                        srtfw.close();
                    }*/
                    if(lrcbw != null){
                        lrcbw.flush();
                        lrcbw.close();
                    }
                    if(lrcosw != null){
                        //lrcosw.flush();
                        lrcosw.close();
                    }
                    if(lrcos != null){
                        lrcos.close();
                    }
                    /*if(lrcfw != null){
                        lrcfw.close();
                    }*/

                    disableHandle(false);
                }

                return true;
            }
        };
    }

    private static int writeTextInLrcAndSrt(double beginTime,double endTime,String value,BufferedWriter srtbw,BufferedWriter lrcbw,int srtrowNum) throws IOException {

        Integer min = 5;
        Integer max = 20;
        Integer defaultIndex = 10;

        String temp = new String(value);

        //获取每一个字的大致时间
        double everyFont = (endTime - beginTime)/value.length();

        System.out.println("拿到的字符串====" + value);

        while (temp.length() > 0){

            int index = 0;

            if(temp.startsWith(",")){
                int del = temp.indexOf(",");
                if(temp.length() > 1){
                    temp = temp.substring(del + 1);
                }else{
                    break;
                }
            }
            temp = StringUtil.checkFirstString(temp,",");
            temp = StringUtil.checkFirstString(temp,".");
            temp = StringUtil.checkFirstString(temp,"，");
            temp = StringUtil.checkFirstString(temp,"。");
            temp = StringUtil.checkFirstString(temp,"?");
            temp = StringUtil.checkFirstString(temp,"？");
            temp = StringUtil.checkFirstString(temp,"!");
            temp = StringUtil.checkFirstString(temp,"？");

            int eDouhao = temp.indexOf(",");
            int eJuhao = temp.indexOf(".");
            int eWenhao = temp.indexOf("?");
            int eGantan = temp.indexOf("!");
            int cDouhao = temp.indexOf("，");
            int cJuhao = temp.indexOf("。");
            int cWenhao = temp.indexOf("？");
            int cGantan = temp.indexOf("！");

            if(eDouhao > min && eDouhao <= max){
                index = eDouhao;
            }
            if(eJuhao > min && eJuhao <= max){
                index = eJuhao;
            }
            if(cDouhao > min && cDouhao <= max){
                index = cDouhao;
            }
            if(cJuhao > min && cJuhao <= max){
                index = cJuhao;
            }
            if(eWenhao > min && eWenhao <= max){
                index = eWenhao;
            }
            if(eGantan > min && eGantan <= max){
                index = eGantan;
            }
            if(cWenhao > min && cWenhao <= max){
                index = cWenhao;
            }
            if(cGantan > min && cGantan <= max){
                index = cGantan;
            }
            if(index <= 0){
                if(temp.length() <= defaultIndex){
                    index = temp.length();
                }else{
                    index = defaultIndex;
                }

            }


            double tempStartTime = endTime - everyFont * temp.length();
            String writeValue = temp.substring(0,index);

            writeValue = StringUtil.checkString(writeValue,",");
            writeValue = StringUtil.checkString(writeValue,"，");
            writeValue = StringUtil.checkString(writeValue,"\\.");
            writeValue = StringUtil.checkString(writeValue,"。");
            writeValue = StringUtil.checkString(writeValue,"\\!");
            writeValue = StringUtil.checkString(writeValue,"\\?");
            writeValue = StringUtil.checkString(writeValue,"？");
            writeValue = StringUtil.checkString(writeValue,"！");
            writeValue = StringUtil.checkString(writeValue,"\\:");
            writeValue = StringUtil.checkString(writeValue,"：");
            writeValue = StringUtil.checkString(writeValue,"“");
            writeValue = StringUtil.checkString(writeValue,"”");
            writeValue = StringUtil.checkString(writeValue,"\"");
            writeValue = StringUtil.checkString(writeValue,"-");
            writeValue = StringUtil.checkString(writeValue,"—");


            temp = temp.substring(index);
            double tempEndTime = endTime - everyFont * temp.length();

            if(writeValue == null || writeValue.trim().isEmpty()){
                continue;
            }
            writeValue = com.github.nobodxbodon.zhconverter.简繁转换类.转换(writeValue, 简繁转换类.目标.繁体);

            //font size
            srtrowNum = srtrowNum + 1;
            srtbw.write(srtrowNum + R);//行号
            srtbw.write(TimeUtil.fotmatDoubleToHMS(tempStartTime > 0.3 ? tempStartTime - 0.3:tempStartTime) + " --> " + TimeUtil.fotmatDoubleToHMS(tempEndTime > 0.301?tempEndTime - 0.301:tempEndTime) + R);//时间
            srtbw.write(writeValue + R);//字幕
            srtbw.write( R);//空行

            lrcbw.write("[" + TimeUtil.fotmatDoubleToMS(tempStartTime) + "]" + writeValue + R);

            System.out.println("组装成的字符串====" + writeValue);

        }
        return srtrowNum;
    }


    @FXML
    public void begianCreateHandle() {

        String path = filePathLab.getText();
        if(path == null || path.trim().isEmpty()){
            AlertUtil.showErrorAlert("请选择存放目录");
            return;
        }
        path = path.trim();
        String fileName = fileNameTxt.getText();
        if(fileName == null || fileName.trim().isEmpty()){
            AlertUtil.showErrorAlert("请填写保存文件名");
            return;
        }
        fileName = fileName.trim();

        if(!fileName.endsWith(".mp3")){
            fileName = fileName + ".mp3";
        }

        //是否覆盖

        //判断文件是否存在
        if(!FileUtil.fileIsExists(path + "/" + fileName)){

            //开启线程启动滚动条
            //Task copyWorker = createWorker(text,path,fileName,spd,pit,vol,per,false);
            createVoice(false);

        }else{
            AlertAskController controller = (AlertAskController) loadFXMLPage("文件提醒", FXMLPage.AlertAsk, false);
            controller.setMainUIController(this);
            controller.showDialogStage();
        }

    }

    public void createVoice(boolean coverFlg){

        String text = setTextTxt.getText();
        if(text == null || text.trim().isEmpty()){
            AlertUtil.showErrorAlert("请输入转化文本");
            return;
        }
        text = text.trim();
        String path = filePathLab.getText();
        if(path == null || path.trim().isEmpty()){
            AlertUtil.showErrorAlert("请选择存放目录");
            return;
        }
        path = path.trim();
        String fileName = fileNameTxt.getText();
        if(fileName == null || fileName.trim().isEmpty()){
            AlertUtil.showErrorAlert("请填写保存文件名");
            return;
        }
        fileName = fileName.trim();

        if(!fileName.endsWith(".mp3")){
            fileName = fileName + ".mp3";
        }

        int spd  = (int) spdScroll.getValue();
        int pit  = (int) pitScroll.getValue();
        int vol  = (int) volScroll.getValue();

        String perName = ((RadioButton) perGroup.getSelectedToggle()).getText();
        int per = 0;
        if("女声 ".equals(perName)){
            per = 0;
        }else if("男声 ".equals(perName)){
            per = 1;
        }else if("情感合成-度丫丫 ".equals(perName)){
            per = 4;
        }else{
            per = 3;
        }

        //开启线程启动滚动条
        Task copyWorker = createWorker(text,path,fileName,spd,pit,vol,per,coverFlg);
        progressBar.progressProperty().unbind();
        progressBar.progressProperty().bind(copyWorker.progressProperty());
        copyWorker.messageProperty().addListener(new ChangeListener<String>() {
            public void changed(ObservableValue<? extends String> observable, String oldValue,
                                String newValue) {
                System.out.println(newValue);
            }
        });
        new Thread(copyWorker).start();
    }

    @FXML
    public void filePathHandle() {

        Stage fileStage = null;
        DirectoryChooser folderChooser = new DirectoryChooser();
        folderChooser.setTitle("文件保存路径");

        String path;

        try{

            File selectedFile = null;

            if(filePathLab.getText() != null && !filePathLab.getText().trim().isEmpty()){

                selectedFile = new File(filePathLab.getText());
                if(selectedFile.exists()){
                    folderChooser.setInitialDirectory(selectedFile);
                }
            }


            selectedFile = folderChooser.showDialog(fileStage);
            if(selectedFile == null){
                filePathLab.setText("");
                return;
            }
            path=selectedFile.getPath();
            if(path != null){
                filePathLab.setText(path);
            }else{
                filePathLab.setText("");
            }
        }
        catch(HeadlessException head){
            System.out.println("Open File Dialog ERROR!");
        }


    }

}
